package org.gm.mybatis.generator.util;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.LinkedList;
import java.util.List;

import org.gm.mybatis.ext.util.StringHelper;
import org.mybatis.generator.api.IntrospectedColumn;
import org.mybatis.generator.api.IntrospectedTable;
import org.mybatis.generator.api.dom.java.Field;
import org.mybatis.generator.api.dom.java.FullyQualifiedJavaType;
import org.mybatis.generator.api.dom.java.InitializationBlock;
import org.mybatis.generator.api.dom.java.Interface;
import org.mybatis.generator.api.dom.java.JavaVisibility;
import org.mybatis.generator.api.dom.java.Method;
import org.mybatis.generator.api.dom.java.Parameter;
import org.mybatis.generator.api.dom.java.TopLevelClass;
import org.mybatis.generator.api.dom.xml.Attribute;
import org.mybatis.generator.api.dom.xml.Element;
import org.mybatis.generator.api.dom.xml.TextElement;
import org.mybatis.generator.api.dom.xml.XmlElement;
import org.mybatis.generator.internal.util.StringUtility;

public class RalationGenerator {
	/**
	 * 创建多对一XML
	 * @param table
	 * @param relationResultMap
	 * @param selectRelationByPrimaryKey
	 * @return
	 */
	public static List<XmlElement> buildManyToOneXML(IntrospectedTable table, 
			XmlElement relationResultMap, XmlElement selectRelationByPrimaryKey){
		
		List<XmlElement> xml = new LinkedList<XmlElement>();
		//读取多对一配置
		String manyToOne = table.getTableConfiguration().getProperty("manyToOne");
		if(StringHelper.notEmpty(manyToOne)){
			String[] pros = manyToOne.split(";");
			for(String pro:pros){
				pro=pro.trim();
				String[] props = pro.split(",");
				String proType = props[0].trim();
				String proName = props[1].trim();
				String colName = props[2].trim();
				String sortCol = "";
				if(props.length==4){
					sortCol = props[3].trim();
				}
				//增加association
				XmlElement association = new XmlElement("association");
				association.addAttribute(new Attribute("property", proName));
				association.addAttribute(new Attribute("javaType", proType));
				association.addAttribute(new Attribute("column", colName));
				String subSelect = table.getContext().getJavaClientGeneratorConfiguration().getTargetPackage()
						.concat(proType.substring(proType.lastIndexOf(".")).concat("Mapper"))
						.concat(".selectByPrimaryKey");
				association.addAttribute(new Attribute("select", subSelect));
				
				relationResultMap.addElement(association);
				
				//创建列表查询SQL语句
				XmlElement list = new XmlElement("select");
				for(int index=0;index<selectRelationByPrimaryKey.getElements().size() - 1;index++){
					Element ae = selectRelationByPrimaryKey.getElements().get(index);
					list.addElement(ae);
				}
				String[] les = selectRelationByPrimaryKey.getElements()
							.get(selectRelationByPrimaryKey.getElements().size()-1)
							.getFormattedContent(0).split(" ");
				StringBuilder lb = new StringBuilder();
				for(int index=0;index<les.length;index++){
					if(index==1){
						lb.append(colName.concat(" "));
					}else{
						lb.append(les[index].concat(" "));
					}
				}
				list.addElement(new TextElement(lb.toString()));
				String javaName = StringHelper.dbNameToJavaName(colName);
				list.addAttribute(new Attribute("id", "selectBy".concat(javaName.substring(0, 1).toUpperCase().concat(javaName.substring(1)))));
				list.addAttribute(new Attribute("resultMap", "BaseResultMap"));
				for(Attribute aa:selectRelationByPrimaryKey.getAttributes()){
					if(aa.getName().equals("parameterType"))list.addAttribute(aa);
				}
				
				if(StringHelper.notEmpty(sortCol)){
					TextElement ele = new TextElement(" order by ".concat(sortCol));
					list.addElement(ele);
					System.out.println(list.getFormattedContent(0));
				}
				
				xml.add(list);
			}
		}

		return xml;
	}
	
	/**
	 * 创建一对多XML
	 * @param table
	 * @param selectByPrimaryKey
	 * @param primaryColumn
	 * @param primaryPro
	 * @param select
	 * @return
	 */
	public static void buildOneToManyXML(IntrospectedTable table, 
			XmlElement relationResultMap){
		//读取数据表主键列
		IntrospectedColumn pkColumn = table.getPrimaryKeyColumns().get(0);
		//读取一对多配置
		String oneToMany = table.getTableConfiguration().getProperty("oneToMany");
		if(StringHelper.notEmpty(oneToMany)){
			String[] pros = oneToMany.split(";");
			for(String pro:pros){
				pro=pro.trim();
				String[] props = pro.split(",");
				String proType = props[0].trim();
				String proName = props[1].trim();
				String colName = props[2].trim();
				//增加collection
				XmlElement collection = new XmlElement("collection");
				collection.addAttribute(new Attribute("property", proName));
				collection.addAttribute(new Attribute("javaType", "ArrayList"));
				collection.addAttribute(new Attribute("column", StringHelper.javaNameToDbName(pkColumn.getJavaProperty())));
				collection.addAttribute(new Attribute("ofType", proType));
				String javaName = StringHelper.dbNameToJavaName(colName);
				String subSelect = table.getContext().getJavaClientGeneratorConfiguration().getTargetPackage()
						.concat(proType.substring(proType.lastIndexOf(".")).concat("Mapper"))
						.concat(".selectBy")
						.concat(javaName.substring(0, 1).toUpperCase())
						.concat(javaName.substring(1));
				collection.addAttribute(new Attribute("select", subSelect));
				
				relationResultMap.addElement(collection);
			}
		}
	}
	
	/**
	 * 创建多对多XML
	 * @param table
	 * @param relationResultMap
	 * @param selectRelationByPrimaryKey
	 * @return
	 */
	public static List<XmlElement> buildManyToManyXML(IntrospectedTable table, 
			XmlElement relationResultMap, XmlElement selectRelationByPrimaryKey, XmlElement baseColumnList){
		//读取数据表主键列
		IntrospectedColumn pkColumn = table.getPrimaryKeyColumns().get(0);
		
		List<XmlElement> xml = new LinkedList<XmlElement>();
		//<property name="manyToOne" value="列表对象类型, 列表对象属性名称, 中间表名称, 中间表映射本表主键的字段名称, 中间表映射列表对象属性表主键的字段名称" />
		//读取多对多配置
		String manyToMany = table.getTableConfiguration().getProperty("manyToMany");
		if(StringHelper.notEmpty(manyToMany)){
			String[] pros = manyToMany.split(";");
			for(String pro:pros){
				String[] proParams = pro.split(",");
				String proType = proParams[0].trim();//列表对象类型
				String proName = proParams[1].trim();//列表对象属性名称
				String lnkTblName = proParams[2].trim();//中间表名称
				String lnkTblLcleName = proParams[3].trim();//中间表映射本表主键的字段名称
				String lnkTblRefName = proParams[4].trim();//中间表映射另一关系表主键的字段名称
				String sortColumn = null;
				if(proParams.length==6)sortColumn=proParams[5].trim();
				
				//增加collection
				XmlElement collection = new XmlElement("collection");
				collection.addAttribute(new Attribute("property", proName));
				collection.addAttribute(new Attribute("javaType", "ArrayList"));
				collection.addAttribute(new Attribute("column", StringHelper.javaNameToDbName(pkColumn.getJavaProperty())));
				collection.addAttribute(new Attribute("ofType", proType));
				String javaName = StringHelper.dbNameToJavaName(lnkTblLcleName);
				String subSelect = table.getContext().getJavaClientGeneratorConfiguration().getTargetPackage()
						.concat(proType.substring(proType.lastIndexOf(".")).concat("Mapper"))
						.concat(".selectBy")
						.concat(javaName.substring(0, 1).toUpperCase())
						.concat(javaName.substring(1));
				collection.addAttribute(new Attribute("select", subSelect));
				
				relationResultMap.addElement(collection);
				
				//生成自身多方Sql查询
				XmlElement list = new XmlElement("select");
				String[] les = selectRelationByPrimaryKey.getElements()
						.get(selectRelationByPrimaryKey.getElements().size()-1)
						.getFormattedContent(0).split(" ");
				for(int index=0;index<selectRelationByPrimaryKey.getElements().size() - 1;index++){
					Element ae = selectRelationByPrimaryKey.getElements().get(index);
					if(StringHelper.notEmpty(sortColumn)){
						if(index==1){
							String baseColumns = "";
							for(Element element:baseColumnList.getElements()){
								if(TextElement.class.isInstance(element)){
									baseColumns = baseColumns.concat(element.getFormattedContent(0));
								}
							}
							baseColumns = "a.".concat(baseColumns.replace(", ", ", a."));
							baseColumns = baseColumns.concat(", b.").concat(sortColumn);
							TextElement te = new TextElement(baseColumns);
							list.addElement(te);
							continue;
						}
						if(index==2){
							StringBuilder elStr = new StringBuilder();
							elStr.append(ae.getFormattedContent(0))
								.append(" a left join ")
								.append(lnkTblName)
								.append(" b on a.id = b.")
								.append(lnkTblLcleName)
								.append(" and b.")
								.append(lnkTblRefName)
								.append(" = ")
								.append(les[les.length-1]);
							TextElement te = new TextElement(elStr.toString());
							list.addElement(te);
							continue;
						}
					}
					list.addElement(ae);
				}
				
				
				StringBuilder lb = new StringBuilder();
				for(int index=0;index<les.length;index++){
					if(index==1){
						if(StringHelper.notEmpty(sortColumn))lb.append("a.");
						lb.append(les[index])
							.append(" in (select ")
							.append(lnkTblLcleName)
							.append(" from ")
							.append(lnkTblName)
							.append(" where ")
							.append(lnkTblRefName)
							.append(" ");
					}else{
						lb.append(les[index].concat(" "));
					}
				}
				lb.append(")");
				list.addElement(new TextElement(lb.toString()));
				javaName = StringHelper.dbNameToJavaName(lnkTblRefName);
				list.addAttribute(new Attribute("id", "selectBy".concat(javaName.substring(0, 1).toUpperCase().concat(javaName.substring(1)))));
				list.addAttribute(new Attribute("resultMap", "BaseResultMap"));
				for(Attribute aa:selectRelationByPrimaryKey.getAttributes()){
					if(aa.getName().equals("parameterType"))list.addAttribute(aa);
				}
				xml.add(list);
			}
		}
		
		return xml;
	}
	
	/**
	 * 创建实体类多对一属性操作方法
	 * @param topLevelClass
	 * @param table
	 * @return
	 */
	public static List<String> buildManyToOneOptMethed(TopLevelClass topLevelClass,
			IntrospectedTable table){
		//多对一关系属性列表
		List<String> relationFields = new LinkedList<String>();
		
		String oneToMany = table.getTableConfigurationProperty("oneToMany");
		if(oneToMany!=null){
			String pros[] = oneToMany.split(";");//根据分号可分割多个属性
			for(String pro:pros){
				pro = pro.trim();
				String[] prop = pro.split(",");//根据逗号分割属性类型和属性名称
				if(prop.length!=3){
					throw new RuntimeException("一对多属性配置错误，该配置应为【属性类型, 属性名称, 从表映射字段名称】组合的字符串。");
				}
				String proType = prop[0].trim();
				String proName = prop[1].trim();
				String meProName = proName.substring(0,1).toUpperCase() + proName.substring(1);
				
				//记录多对一关系对象
				relationFields.add(proName);
				
				//插入多对一字段与getter,setter
				Field field = new Field();
				field.setVisibility(JavaVisibility.PROTECTED);
				field.setName(proName);
				FullyQualifiedJavaType javaType = new FullyQualifiedJavaType("java.util.List<" + proType + ">");
				field.setType(javaType);
				topLevelClass.addField(field);
				Method method = new Method();
				method.setName("get" + meProName);
				method.setVisibility(JavaVisibility.PUBLIC);
				method.setReturnType(field.getType());
				method.addBodyLine("return " + proName +";");
				topLevelClass.addMethod(method);
				method = new Method();
				method.setName("set" + meProName);
				method.setVisibility(JavaVisibility.PUBLIC);
				Parameter parameter = new Parameter(field.getType(), proName);
				method.addParameter(parameter);
				method.addBodyLine("this." + proName + "=" +  proName + ";");
				topLevelClass.addMethod(method);
				//导包
				topLevelClass.addImportedType(javaType);
				
			}
		}
		return relationFields;
	}
	
	/**
	 * 创建实体类一对多属性操作方法
	 * @param topLevelClass
	 * @param table
	 * @return
	 */
	public static List<String> buildOneToManyOptMethed(TopLevelClass topLevelClass,
			IntrospectedTable table){
		//一对多关系属性列表
		List<String> relationFields = new LinkedList<String>();
		
		String manyToOne = table.getTableConfigurationProperty("manyToOne");
		if(manyToOne!=null){
			String pros[] = manyToOne.split(";");//根据分号可分割多个属性
			for(String pro:pros){
				pro = pro.trim();
				String[] prop = pro.split(",");//根据逗号分割属性类型和属性名称
				if(prop.length<3){
					throw new RuntimeException("多对一属性配置错误，该配置应为【属性类型, 属性名称, 主表主键字段名称, (可选List排序字段)】组合的字符串。");
				}
				String proType = prop[0].trim();
				String proName = prop[1].trim();
				String meProName = proName.substring(0,1).toUpperCase() + proName.substring(1);
				
				
				//记录一对多关系对象
				relationFields.add(proName);
				
				//插入一对多字段与getter,setter
				Field field = new Field();
				field.setVisibility(JavaVisibility.PROTECTED);
				field.setName(proName);
				FullyQualifiedJavaType javaType = new FullyQualifiedJavaType(proType);
				field.setType(javaType);
				topLevelClass.addField(field);
				Method method = new Method();
				method.setName("get" + meProName);
				method.setVisibility(JavaVisibility.PUBLIC);
				method.setReturnType(field.getType());
				method.addBodyLine("return " + proName +";");
				topLevelClass.addMethod(method);
				method = new Method();
				method.setName("set" + meProName);
				method.setVisibility(JavaVisibility.PUBLIC);
				Parameter parameter = new Parameter(field.getType(), proName);
				method.addParameter(parameter);
				method.addBodyLine("this." + proName + "=" +  proName + ";");
				topLevelClass.addMethod(method);
				//导包
				topLevelClass.addImportedType(javaType);
				
			}
		}
		return relationFields;
	}
	
	/**
	 * 创建实体类一对多属性操作方法
	 * @param topLevelClass
	 * @param table
	 * @return
	 */
	public static List<String> buildManyToManyOptMethed(TopLevelClass topLevelClass,
			IntrospectedTable table){
		//多对多关系属性列表
		List<String> relationFields = new LinkedList<String>();
		
		String manyToMany = table.getTableConfigurationProperty("manyToMany");
		if(StringHelper.notEmpty(manyToMany)){
			String pros[] = manyToMany.split(";");//根据分号可分割多个属性
			for(String pro:pros){
				pro = pro.trim();
				String[] prop = pro.split(",");//根据逗号分割属性类型和属性名称
				if(prop.length<5){
					throw new RuntimeException("多对多属性配置错误，该配置属性值列表【列表对象类型, 列表对象属性名称, 中间表名称, 中间表映射本表主键的字段名称, 中间表映射另一关系表主键的字段名称, (可选List排序字段)】。");
				}
				String proType = prop[0].trim();
				String proName = prop[1].trim();
				String meProName = proName.substring(0,1).toUpperCase() + proName.substring(1);
				
				//记录多对多关系对象
				relationFields.add(proName);
				
				//插入多对多字段与getter,setter
				Field field = new Field();
				field.setVisibility(JavaVisibility.PROTECTED);
				field.setName(proName);
				FullyQualifiedJavaType javaType = new FullyQualifiedJavaType("java.util.List<" + proType + ">");
				field.setType(javaType);
				topLevelClass.addField(field);
				Method method = new Method();
				method.setName("get" + meProName);
				method.setVisibility(JavaVisibility.PUBLIC);
				method.setReturnType(field.getType());
				method.addBodyLine("return " + proName +";");
				topLevelClass.addMethod(method);
				method = new Method();
				method.setName("set" + meProName);
				method.setVisibility(JavaVisibility.PUBLIC);
				Parameter parameter = new Parameter(field.getType(), proName);
				method.addParameter(parameter);
				method.addBodyLine("this." + proName + "=" +  proName + ";");
				topLevelClass.addMethod(method);
				//导包
				topLevelClass.addImportedType(javaType);
				
			}
		}
		return relationFields;
	}
	
	/**
	 * 创建关系字段块，让应用程序开发者了解该类的关系类
	 * @param topLevelClass
	 * @param relationFields
	 */
	public static void generatRelationBlock(TopLevelClass topLevelClass, List<String> relationFields){
		Field field = new Field();
		field.setVisibility(JavaVisibility.PROTECTED);
		field.setName("relationFields");
		FullyQualifiedJavaType javaType = new FullyQualifiedJavaType("java.util.List<String>");
		field.setType(javaType);
		topLevelClass.addField(field);
		InitializationBlock ib = new InitializationBlock();
		ib.addBodyLine("relationFields = new LinkedList<String>();");
		for(String arr:relationFields){
			ib.addBodyLine("relationFields.add(\""+arr+"\");");
		}
		topLevelClass.addInitializationBlock(ib);
		Method method = new Method();
		method.setName("getRelationFields");
		method.setVisibility(JavaVisibility.PUBLIC);
		method.setReturnType(field.getType());
		method.addBodyLine("return relationFields;");
		topLevelClass.addMethod(method);
		topLevelClass.addImportedType("java.util.List");
		topLevelClass.addImportedType("java.util.LinkedList");
		method = new Method();
		method.setName("setRelationFields");
		method.setVisibility(JavaVisibility.PUBLIC);
		method.addParameter(new Parameter(new FullyQualifiedJavaType("java.util.List<String>"), "relationFields"));
		method.addBodyLine("this.relationFields = relationFields;");
		topLevelClass.addMethod(method);
	}
	
	/**
	 * 创建该表需要进行md5版本计算的字段
	 * @param topLevelClass
	 * @param table
	 */
	public static void generateMd5Optional(TopLevelClass topLevelClass,
			IntrospectedTable table){
		String md5Config = table.getTableConfigurationProperty("md5");
		InitializationBlock ib = new InitializationBlock();
		if(md5Config!=null && !md5Config.equals("")){
			//加入md5配置属性
			Field md5 = new Field();
			md5.setVisibility(JavaVisibility.PROTECTED);
			md5.setName("md5Cols");
			FullyQualifiedJavaType md5JavaType = new FullyQualifiedJavaType("java.util.List<String>");
			md5.setType(md5JavaType);
			topLevelClass.addField(md5);
			//md5 getter and setter方法
			Method md5Getter = new Method();
			md5Getter.setName("getMd5Cols");
			md5Getter.setVisibility(JavaVisibility.PUBLIC);
			md5Getter.setReturnType(md5.getType());
			md5Getter.addBodyLine("return md5Cols;");
			topLevelClass.addMethod(md5Getter);
			md5Getter = new Method();
			md5Getter.setName("setMd5Cols");
			md5Getter.setVisibility(JavaVisibility.PUBLIC);
			md5Getter.addParameter(new Parameter(new FullyQualifiedJavaType("java.util.List<String>"), "md5Cols"));
			md5Getter.addBodyLine("this.md5Cols=md5Cols;");
			topLevelClass.addMethod(md5Getter);
			
			//MD5属性静态初始化
			ib.addBodyLine("md5Cols = new LinkedList<String>();");
			
			String cfg[] = md5Config.split(",");
			for(String config:cfg){
				config = config.trim();
				
				StringBuffer propName = new StringBuffer();
				String[] dname = config.split("_");
				for (int index = 0; index < dname.length; index++) {
					if (index == 0) {
						propName.append(dname[index]);
					} else {
						String first = dname[index].substring(0, 1);
						String other = dname[index].substring(1);
						propName.append(first.toUpperCase());
						propName.append(other);
					}
				}
				ib.addBodyLine("md5Cols.add(\""+propName+"\");");
			}
			
			//序列化md5属性值为字符串
			Method md5Method = new Method();
			md5Method.setName("md5ColString");
			md5Method.setVisibility(JavaVisibility.PUBLIC);
			md5Method.setReturnType(FullyQualifiedJavaType.getStringInstance());
			md5Method.addException(new FullyQualifiedJavaType("java.lang.Exception"));
			md5Method.addBodyLine("StringBuilder colStr = new StringBuilder();");
			md5Method.addBodyLine("for(String col:md5Cols){");
			md5Method.addBodyLine("Object colValue = BlueGridUtil.get(this, col);");
			md5Method.addBodyLine("if(StringHelper.isEmpty(colValue))continue;");
			md5Method.addBodyLine("if(colValue instanceof BigDecimal || colValue instanceof String){");
			md5Method.addBodyLine("colStr.append(colValue.toString());");
			md5Method.addBodyLine("}");
			md5Method.addBodyLine("if(colValue instanceof Double){");
			md5Method.addBodyLine("colStr.append(String.valueOf((Double)colValue));");
			md5Method.addBodyLine("}");
			md5Method.addBodyLine("if(colValue instanceof Long){");
			md5Method.addBodyLine("colStr.append(String.valueOf((Long)colValue));");
			md5Method.addBodyLine("}");
			md5Method.addBodyLine("if(colValue instanceof Integer){");
			md5Method.addBodyLine("colStr.append(String.valueOf((Integer)colValue));");
			md5Method.addBodyLine("}");
			md5Method.addBodyLine("Field cf = BlueGridUtil.getDeclaredField(getClass(), col);");
			md5Method.addBodyLine("if(cf.isAnnotationPresent(DateTimeFormat.class)){");
			md5Method.addBodyLine("DateTimeFormat datetimeFormat = cf.getAnnotation(DateTimeFormat.class);");
			md5Method.addBodyLine("colStr.append(StringHelper.formatDate(((Date)colValue), datetimeFormat.pattern()));");
			md5Method.addBodyLine("}");
			md5Method.addBodyLine("}");
			md5Method.addBodyLine("return colStr.toString();");
			topLevelClass.addMethod(md5Method);
			topLevelClass.addImportedType("java.math.BigDecimal");
			topLevelClass.addImportedType("java.util.Date");
			topLevelClass.addImportedType("com.pnlan.bluegrid.common.StringHelper");
			//计算md5值的方法
			Method md5ValueMethod = new Method();
			md5ValueMethod.setName("md5");
			md5ValueMethod.setVisibility(JavaVisibility.PUBLIC);
			md5ValueMethod.setReturnType(FullyQualifiedJavaType.getStringInstance());
			md5ValueMethod.addException(new FullyQualifiedJavaType("java.lang.Exception"));
			md5ValueMethod.addBodyLine("String md5 = null;");
			md5ValueMethod.addBodyLine("char[] hexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };");
			md5ValueMethod.addBodyLine("MessageDigest md = MessageDigest.getInstance(\"MD5\");");
			md5ValueMethod.addBodyLine("byte[] bt = md5ColString().getBytes(\"utf-8\");");
			md5ValueMethod.addBodyLine("md.update(bt);");
			md5ValueMethod.addBodyLine("byte[] tmp = md.digest();");
			md5ValueMethod.addBodyLine("char[] str = new char[32];");
			md5ValueMethod.addBodyLine("for (int i = 0, j = 0; i < 16; i++) {");
			md5ValueMethod.addBodyLine("byte b = tmp[i];");
			md5ValueMethod.addBodyLine("str[j++] = hexDigits[b >>> 4 & 0xf];");
			md5ValueMethod.addBodyLine("str[j++] = hexDigits[b & 0xf];");
			md5ValueMethod.addBodyLine("}");
			md5ValueMethod.addBodyLine("md5 = new String(str);");
			md5ValueMethod.addBodyLine("return md5;");
			topLevelClass.addMethod(md5ValueMethod);
			topLevelClass.addImportedType("java.security.MessageDigest");
		}
	}

	public static void generateMapperExtends(Interface interfaze, TopLevelClass topLevelClass,
			IntrospectedTable table, String superMapper){
		if (StringUtility.stringHasValue(superMapper)) {
			// 获取实体类
			FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(
					table.getBaseRecordType());
			FullyQualifiedJavaType entityExampleType = new FullyQualifiedJavaType(
					table.getExampleType());
			// import接口
			interfaze.addImportedType(new FullyQualifiedJavaType(superMapper));
			interfaze.addSuperInterface(new FullyQualifiedJavaType(
					superMapper.concat("<")
						.concat(entityType.getShortName())
						.concat(", ")
						.concat(entityExampleType.getShortName())
						.concat(">")
			));
		
			// import实体类
			interfaze.addImportedType(entityType);
	
			// 引入Repository注解 创建注解扫描
			interfaze.addImportedType(new FullyQualifiedJavaType(
					"org.springframework.stereotype.Repository"));
			String resName = table.getMyBatis3XmlMapperFileName();
			resName = resName.substring(0, resName.length() - 4);
			String fc = resName.substring(0, 1);
			resName = resName.substring(1);
			resName = fc.toLowerCase().concat(resName);
			interfaze.addAnnotation("@Repository(\"".concat(resName).concat("\")"));
		}
	}
	
	public static void generatorDefaultService(Interface interfaze, TopLevelClass topLevelClass, IntrospectedTable table, 
			String serviceProjectPath, String baseServiceType, String baseServiceImplType) throws IOException{
		// 获取实体类
		FullyQualifiedJavaType entityType = new FullyQualifiedJavaType(table.getBaseRecordType());
		FullyQualifiedJavaType entityExampleType = new FullyQualifiedJavaType(table.getExampleType());
		
		//读取配置属性
		String servicePkg = table.getTableConfiguration().getProperty("servicePkg");
		String serviceImplPkg = table.getTableConfiguration().getProperty("serviceImplPkg");
		//服务层接口是否已创建
		boolean serviceCreated = false;
		/******创建服务层接口*******/
		if (StringHelper.notEmpty(serviceProjectPath) && StringHelper.notEmpty(baseServiceType) && StringHelper.notEmpty(servicePkg)) {
			String serviceName = entityType.getShortName().concat("Service.java");
			String servicePath = serviceProjectPath.concat("/").concat(servicePkg.replace(".", "/"));
			String serviceFilePath = serviceProjectPath.concat("/").concat(servicePkg.replace(".", "/")).concat("/").concat(serviceName);
			File serviceFile = new File(serviceFilePath);
			if(!serviceFile.exists()){
				Interface serviceInterface = new Interface(servicePkg.concat(".").concat(entityType.getShortName()).concat("Service"));
				serviceInterface.addImportedType(entityType);
				serviceInterface.addImportedType(entityExampleType);
				FullyQualifiedJavaType suptp = new FullyQualifiedJavaType(baseServiceType);
				suptp.addTypeArgument(entityType);
				suptp.addTypeArgument(entityExampleType);

				serviceInterface.addImportedType(suptp);
				serviceInterface.setVisibility(JavaVisibility.PUBLIC);
				serviceInterface.addSuperInterface(suptp);
				String serviceCode = serviceInterface.getFormattedContent();
				
				//些服务接口文件
				File servicePathFile = new File(servicePath);
				if(!servicePathFile.exists())servicePathFile.mkdirs();
				serviceFile.createNewFile();
				OutputStream fout = new FileOutputStream(serviceFile);
				fout.write(serviceCode.getBytes());
				fout.flush();
				fout.close();
			}
			serviceCreated = true;
		}else{
			System.out.println("[System.warn] ".concat(entityType.getShortName().concat("Service.java")).concat("接口类的创建必须同时设置以下属性(配置例子见请参见DOC)："));
			System.out.println("              ".concat("1. plugin标签的serviceProjectPath属性。"));
			System.out.println("              ".concat("2. plugin标签的baseService属性。"));
			System.out.println("              ".concat("3. table标签的servicePkg属性。"));
		}
		
		/******创建服务层实现类*******/
		if(!serviceCreated){
			System.out.println("[System.warn] ".concat("服务层接口未创建的情况下不能创建服务层实现类!"));
		}else{
			if (StringHelper.notEmpty(serviceProjectPath) && StringHelper.notEmpty(baseServiceImplType) && StringHelper.notEmpty(serviceImplPkg)) {
				String serviceImplName = entityType.getShortName().concat("ServiceImpl.java");
				String serviceImplPath = serviceProjectPath.concat("/").concat(serviceImplPkg.replace(".", "/"));
				String serviceImplFilePath = serviceProjectPath.concat("/").concat(serviceImplPkg.replace(".", "/")).concat("/").concat(serviceImplName);
				File serviceImplFile = new File(serviceImplFilePath);
				if(!serviceImplFile.exists()){
					TopLevelClass serviceImpl = new TopLevelClass(serviceImplPkg.concat(".").concat(entityType.getShortName()).concat("ServiceImpl"));
					serviceImpl.addImportedType(entityType);
					serviceImpl.addImportedType(entityExampleType);
					serviceImpl.addImportedType(new FullyQualifiedJavaType("org.springframework.stereotype.Service"));
					
					FullyQualifiedJavaType suptp = new FullyQualifiedJavaType(baseServiceImplType);
					suptp.addTypeArgument(entityType);
					suptp.addTypeArgument(entityExampleType);
					serviceImpl.addImportedType(suptp);
					serviceImpl.setSuperClass(suptp);
					
					suptp = new FullyQualifiedJavaType(servicePkg.concat(".").concat(entityType.getShortName()).concat("Service"));
					serviceImpl.addImportedType(suptp);
					serviceImpl.addSuperInterface(suptp);
					
					StringBuffer anno = new StringBuffer();
					String entityShortName = entityType.getShortName();
					entityShortName = entityShortName.substring(0,1).toLowerCase().concat(entityShortName.substring(1));
					anno.append("@Service(\"")
						.append(entityShortName)
						.append("Service\")");
					serviceImpl.addAnnotation(anno.toString());
					
					Field mapperField = new Field();
					String mapperName = interfaze.getType().getShortName();
					mapperName = mapperName.substring(0,1).toLowerCase().concat(mapperName.substring(1));
					mapperField.setName(mapperName);
					mapperField.setType(interfaze.getSuperInterfaceTypes().iterator().next());
					anno = new StringBuffer();
					anno.append("@Resource(name=\"")
						.append(mapperName)
						.append("\")");
					mapperField.addAnnotation(anno.toString());
					mapperField.setVisibility(JavaVisibility.PRIVATE);
					serviceImpl.addField(mapperField);
					serviceImpl.addImportedType(interfaze.getSuperInterfaceTypes().iterator().next());
					serviceImpl.addImportedType("javax.annotation.Resource");
					
					Method method = new Method();
					method.setName("getDAO");
					method.setReturnType(interfaze.getSuperInterfaceTypes().iterator().next());
					method.addAnnotation("@Override");
					method.setVisibility(JavaVisibility.PROTECTED);
					method.addBodyLine("return " + mapperField.getName() + ";");
					serviceImpl.addMethod(method);
					
					serviceImpl.setVisibility(JavaVisibility.PUBLIC);
					
					String implCode = serviceImpl.getFormattedContent();
					
					//写服务接口文件
					File serviceImplPathFile = new File(serviceImplPath);
					if(!serviceImplPathFile.exists())serviceImplPathFile.mkdirs();
					serviceImplFile.createNewFile();
					OutputStream fout = new FileOutputStream(serviceImplFile);
					fout.write(implCode.getBytes());
					fout.flush();
					fout.close();
				}
				serviceCreated = true;
			}else{
				System.out.println("[System.warn] ".concat(entityType.getShortName().concat("ServiceImpl.java")).concat("实现类的创建必须同时设置以下属性(配置例子见请参见DOC)："));
				System.out.println("              ".concat("1. plugin标签的serviceProjectPath属性。"));
				System.out.println("              ".concat("2. plugin标签的baseServiceImpl属性。"));
				System.out.println("              ".concat("3. table标签的serviceImplPkg属性。"));
			}
		}
	}
}